/*=========================================================================
 *
 *  Copyright Arash Akbarinia
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <itkImage.h>
#include <itkGDCMImageIO.h>
#include <itkGDCMSeriesFileNames.h>
#include <itkImageSeriesReader.h>
#include <itkImageFileWriter.h>

typedef itk::GDCMImageIO ImageIOType;

void PrintSeriesInformation ( const ImageIOType::Pointer DicomIO )
{
  typedef itk::MetaDataDictionary DictionaryType;

  const DictionaryType& dictionary = DicomIO->GetMetaDataDictionary();

  typedef itk::MetaDataObject< std::string > MetaDataStringType;

  std::string entryId = "0008|103e";

  DictionaryType::ConstIterator tagItr = dictionary.Find ( entryId );

  if ( tagItr == dictionary.End() )
    {
      std::cerr << "Tag " << entryId;
      std::cerr << " not found in the DICOM header" << std::endl;
      return;
    }

  MetaDataStringType::ConstPointer entryvalue = dynamic_cast< const MetaDataStringType* > ( tagItr->second.GetPointer() );

  if ( entryvalue )
    {
      std::string tagvalue = entryvalue->GetMetaDataObjectValue();
      std::cout << tagvalue << std::endl;
    }
  else
    {
      std::cerr << "Entry was not of string type" << std::endl;
      return;
    }
}

int main ( int argc, char** argv )
{

  if ( argc < 3 )
    {
      std::cerr << "Usage: " << std::endl;
      std::cerr << argv[0] << " DicomDirectory  outputFileName  [seriesName]"
                << std::endl;
      return EXIT_FAILURE;
    }

  typedef signed short PixelType;
  const unsigned int Dimension = 3;

  typedef itk::Image< PixelType, Dimension > ImageType;

  typedef itk::ImageSeriesReader< ImageType > ReaderType;

  typedef itk::GDCMSeriesFileNames NamesGeneratorType;
  NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();

  nameGenerator->SetUseSeriesDetails ( true );
  nameGenerator->AddSeriesRestriction ( "0008|0021" );

  nameGenerator->SetDirectory ( argv[1] );

  try
    {
      std::cout << std::endl << "The directory: " << std::endl;
      std::cout << std::endl << argv[1] << std::endl << std::endl;
      std::cout << "Contains the following DICOM Series: ";
      std::cout << std::endl << std::endl;

      typedef std::vector< std::string > SeriesIdContainer;
      typedef std::vector< std::string > FileNamesContainer;

      const SeriesIdContainer& seriesUID = nameGenerator->GetSeriesUIDs();

      SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
      SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
      unsigned int ImageNumber = 0;
      while ( seriesItr != seriesEnd )
        {
          ReaderType::Pointer reader = ReaderType::New();
          ImageIOType::Pointer dicomIO = ImageIOType::New();
          reader->SetImageIO ( dicomIO );

          std::string seriesIdentifier = seriesItr->c_str();
          std::cout << "[" << ImageNumber << "] ";
          FileNamesContainer fileNames = nameGenerator->GetFileNames ( seriesIdentifier );
          reader->SetFileNames ( fileNames );

          try
            {
              reader->Update();
              PrintSeriesInformation ( dicomIO );
            }
          catch ( itk::ExceptionObject &ex )
            {
              std::cout << ex << std::endl;
              return EXIT_FAILURE;
            }

          ++seriesItr;
          ImageNumber++;
        }

      int UserChoice;
      std::cout << "Which series number you want to read" << std::endl;
      std::cin >> UserChoice;
      while ( UserChoice >= seriesUID.size() )
        {
          std::cout << "Which series number you want to read" << std::endl;
          std::cin >> UserChoice;
        }

      typedef itk::ImageFileWriter< ImageType > WriterType;
      WriterType::Pointer writer = WriterType::New();

      writer->SetFileName ( argv[2] );

      ReaderType::Pointer reader = ReaderType::New();
      ImageIOType::Pointer dicomIO = ImageIOType::New();
      reader->SetImageIO ( dicomIO );
      writer->SetInput ( reader->GetOutput() );
      FileNamesContainer fileNames = nameGenerator->GetFileNames ( seriesUID[UserChoice] );
      reader->SetFileNames ( fileNames );

      std::cout << "Writing the image as " << std::endl << std::endl;
      std::cout << argv[2] << std::endl << std::endl;

      writer->Update();
    }
  catch ( itk::ExceptionObject& ex )
    {
      std::cout << ex << std::endl;
      return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;
}
